package com.nkym.wypan.controller;/*
 * @ClassName FileInfoController
 * @Desc TODO
 * @Author 19637
 * @Date 2023/6/10 10:21
 * @Version 1.0
 */

import com.nkym.wypan.annotation.LoginIgnore;
import com.nkym.wypan.enums.ResponseStatus;
import com.nkym.wypan.exception.BusinessException;
import com.nkym.wypan.model.context.fileinfo.*;
import com.nkym.wypan.model.req.fileinfo.*;
import com.nkym.wypan.model.resp.ChunkUploadVo;
import com.nkym.wypan.response.BaseResponse;
import com.nkym.wypan.service.FileInfoService;
import com.nkym.wypan.utils.UserContextHolder;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Set;

@RestController
@Api(tags = "文件模块")
@RequestMapping("/file-info")
@Slf4j
public class FileInfoController {

    @Autowired
    FileInfoService fileInfoService;


    @PostMapping("/sec-upload")
    @ApiOperation("文件秒传")
    public BaseResponse secUpload(@Valid @RequestBody
                                  SecUploadReq secUploadReq) {
        fileInfoService.secUpload(secUploadReq);
        return BaseResponse.ok(ResponseStatus.UPLOAD_SUCCESS);
    }

    @PostMapping("/sharding-query")
    @ApiOperation("分片查询")
    public BaseResponse shardingQuery(@Valid @RequestBody
                                      ShardingQueryReq shardingQueryReq) {
        ShardingQueryContext context = new ShardingQueryContext();
        Long userId = UserContextHolder.getId();
        context.setUserId(userId);
        context.setIdentifier(shardingQueryReq.getIdentifier());
        Set<Integer> chunkNumbers = fileInfoService.shardingQuery(context);
        return BaseResponse.ok(chunkNumbers);
    }

    @PostMapping("/multipart-upload")
    @ApiOperation(
            value = "分片上传",
            notes = "分片上传接口"
    )
    public BaseResponse<ChunkUploadVo> chunkUpload(@Valid ChunkUploadReq chunkUploadReq) {
        ChunkUploadContext chunkUploadContext = getChunkUploadContext(chunkUploadReq);
        ChunkUploadVo uploadVo = fileInfoService.chunkUpload(chunkUploadContext);
        return BaseResponse.ok(uploadVo);
    }

    @PostMapping("/chunk-merge")
    @ApiOperation(
            value = "分片合并",
            notes = "分片合并接口"
    )
    public BaseResponse chunkMerge(@Valid @RequestBody
                                   ChunkMergeReq mergeReq) {
        ChunkMergeContext context = cover2MergeContext(mergeReq);
        fileInfoService.chunkMerge(context);
        return BaseResponse.ok(ResponseStatus.UPLOAD_SUCCESS);
    }


    @PostMapping("/upload")
    @ApiOperation(
            value = "单文件上传",
            notes = "单文件上传接口"
    )
    public BaseResponse upload(@Valid
                               UploadReq uploadReq) throws IOException {
        Long parentId = uploadReq.getParentId();
        String identifier = uploadReq.getIdentifier();
        MultipartFile file = uploadReq.getFile();
        String filename = file.getOriginalFilename();
        long size = file.getSize();
        InputStream inputStream = file.getInputStream();
        UploadContext uploadContext = coverToUploadContext(filename, parentId, size, identifier, inputStream);
        fileInfoService.upload(uploadContext);
        return BaseResponse.ok(ResponseStatus.UPLOAD_SUCCESS);
    }

    @GetMapping("/download/{code}")
    @ApiOperation(
            value = "文件下载",
            notes = "文件下载接口"
    )
    @LoginIgnore
    public void download(@PathVariable("code") String code, HttpServletResponse response) throws IOException {
        fileInfoService.download(code, response);

    }

    @GetMapping("/preview/{code}")
    @ApiOperation(
            value = "文件预览",
            notes = "文件预览接口",
            produces = MediaType.APPLICATION_OCTET_STREAM_VALUE
    )
    @LoginIgnore
    public ResponseEntity<Resource> preview(@PathVariable("code") String code) throws IOException {
        return fileInfoService.preview(code);
    }

    @PostMapping("/source-code")
    @ApiOperation(
            value = "获取资源码",
            notes = "获取资源码接口"
    )
    public BaseResponse<String> getSourceCode(@Valid @RequestBody
                                              SourceCodeReq req) throws IOException {
        String fid = req.getFileId();
        Long userId = UserContextHolder.getId();
        SourceCodeContext sourceCodeContext = new SourceCodeContext();
        Long fileId = Long.parseLong(fid);
        sourceCodeContext.setFileId(fileId);
        sourceCodeContext.setUserId(userId);
        String code = fileInfoService.getSourceCode(sourceCodeContext);
        return BaseResponse.ok(code);
    }


    /**
     * ---------------------------------private---------------------------------------------------------------------
     */


    private ChunkMergeContext cover2MergeContext(ChunkMergeReq mergeReq) {
        Long parentId = mergeReq.getParentId();
        String identifier = mergeReq.getIdentifier();
        Integer chunkTotalNumber = mergeReq.getChunkTotalNumber();
        String filename = mergeReq.getFilename();
        Long userId = UserContextHolder.getId();
        ChunkMergeContext context = new ChunkMergeContext();
        context.setChunkTotalNumber(chunkTotalNumber);
        context.setIdentifier(identifier);
        context.setParentId(parentId);
        context.setFilename(filename);
        context.setUserId(userId);
        return context;
    }

    private UploadContext coverToUploadContext(String filename, Long parentId, Long fileSize, String identifier, InputStream stream) {
        UploadContext uploadContext = new UploadContext();
        uploadContext.setStream(stream);
        uploadContext.setParentId(parentId);
        uploadContext.setFileSize(fileSize);
        uploadContext.setFilename(filename);
        uploadContext.setIdentifier(identifier);
        return uploadContext;
    }

    @NotNull
    private static ChunkUploadContext getChunkUploadContext(ChunkUploadReq chunkUploadReq) {
        Integer chunkNumber = chunkUploadReq.getChunkNumber();
        Integer totalChunks = chunkUploadReq.getTotalChunks();
        String identifier = chunkUploadReq.getIdentifier();
        MultipartFile file = chunkUploadReq.getFile();
        Long fileSize = chunkUploadReq.getFileSize();
        Long userId = UserContextHolder.getId();
        try {
            InputStream inputStream = file.getInputStream();
            ChunkUploadContext chunkUploadContext = new ChunkUploadContext();
            chunkUploadContext.setChunkFileSize(file.getSize());
            chunkUploadContext.setChunkNumber(chunkNumber);
            chunkUploadContext.setIdentifier(identifier);
            chunkUploadContext.setTotalChunks(totalChunks);
            chunkUploadContext.setFileSize(fileSize);
            chunkUploadContext.setInputStream(inputStream);
            chunkUploadContext.setUserId(userId);
            return chunkUploadContext;
        } catch (Exception e) {
            log.error("{}", e);
            throw new BusinessException(ResponseStatus.CHUNK_UPLOAD_FAIL);
        }

    }

}
